package com.sky.aspect;

import com.sky.anno.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import org.apache.commons.lang3.ObjectUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;

@Aspect
@Component
public class AutoFillAspect {
    /**
     * 切面类，用于将增加和修改方法中冗余的代码提取出来
     */
    @Pointcut("@annotation(com.sky.anno.AutoFill) && execution(*  com.sky.mapper.*.*(..))") //提取共用表达式,还要指定在mapper包下
    public void pc() {
    }

    @Before("pc() && @annotation(autoFill)")  //autoFill是参数,推荐这种注入方式
    public void autoFill(JoinPoint jp, AutoFill autoFill) throws IllegalAccessException {    //自动注入autoFill
        Object[] args = jp.getArgs();    //获取参数
        if (ObjectUtils.isEmpty(args)) {
            return;
        }
        Object parameter = args[0];
        OperationType value = autoFill.value();    //可以直接拿
        Field[] fields = parameter.getClass().getDeclaredFields();  //记得加Declared
        //通过map集合拿更高效,同时能够判断属性是否存在
        Map<String, Field> fileMap = Arrays.stream(fields).collect(Collectors.toMap(f -> f.getName(), Function.identity()));
        switch (value) {
            case INSERT: {
                fieldFill(parameter, fileMap, "createTime");
                fieldFill(parameter, fileMap, "createUser");
                fieldFill(parameter, fileMap, "updateTime");
                fieldFill(parameter, fileMap, "updateUser");
                break;
            }
            case UPDATE: {
                fieldFill(parameter, fileMap, "updateTime");
                fieldFill(parameter, fileMap, "updateUser");
                break;
            }
        }
    }

    //将冗余代码整合进方法
    public void fieldFill(Object entity, Map<String, Field> fileMap, String fileName) throws IllegalAccessException {
        Field field = fileMap.get(fileName);
        if (field == null) {   //判断属性是否存在
            return;
        }
        field.setAccessible(true);   //暴力反射
        if (field.getType() == LocalDateTime.class) {   //根据不同属性填入不同值
            field.set(entity, LocalDateTime.now());
        } else {
            field.set(entity, BaseContext.getCurrentId());
        }
    }
    /*@Before("pc()")
    public void autoFill(JoinPoint jp){    //ProceedingJoinPoint只能使用在around上，JoinPoint无法控制方法运行*/
    /*@Before("pc() && @annotation(autoFill)")  //autoFill是参数
    public void autoFill(JoinPoint jp,AutoFill autoFill){    //自动注入autoFill
        Object[] args = jp.getArgs();    //获取参数
        if (ObjectUtils.isEmpty(args)){
            return;
        }
        LocalDateTime now = LocalDateTime.now();
        Long id = BaseContext.getCurrentId();     //冗余代码
        Object parameter = args[0];
        MethodSignature signature = (MethodSignature)jp.getSignature();
        String methodName = signature.getName();
        String className = signature.getDeclaringTypeName();  //获取类名和方法名
        try {
//            Method method = Class.forName(className).getMethod(methodName,parameter.getClass());  //通过反射拿到方法对象
//            OperationType value = method.getAnnotation(AutoFill.class).value();   //拿到方法上注解值方便一下判断
            OperationType value = autoFill.value();    //可以直接拿
            switch (value){
                case INSERT:{
                    //通过反射拿到对应方法
                    Method setCreateTime = parameter.getClass().getMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                    Method setUpdateTime = parameter.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                    Method setCreateUser = parameter.getClass().getMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                    Method setUpdateUser = parameter.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                    //执行方法
                    setCreateUser.invoke(parameter, id);
                    setUpdateUser.invoke(parameter, id);
                    setCreateTime.invoke(parameter, now);
                    setUpdateTime.invoke(parameter, now);
                }
                case UPDATE:{
                    //通过反射拿到对应方法
                    Method setUpdateTime = parameter.getClass().getMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                    Method setUpdateUser = parameter.getClass().getMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);
                    //执行方法
                    setUpdateUser.invoke(parameter, id);
                    setUpdateTime.invoke(parameter, now);
                }
            }
        } catch (Throwable e) {
            e.printStackTrace();
        }
    }*/

}

